package com.zyx.crawlerdemo.makrocrawler.main;

import cn.edu.hfut.dmic.webcollector.model.CrawlDatum;
import cn.edu.hfut.dmic.webcollector.model.CrawlDatums;
import cn.edu.hfut.dmic.webcollector.model.Page;
import cn.edu.hfut.dmic.webcollector.plugin.berkeley.BreadthCrawler;
import java.util.ArrayList;
import java.util.List;

import com.zyx.crawlerdemo.makrocrawler.db.MysqlControl;
import com.zyx.crawlerdemo.makrocrawler.model.ParameterModel;
import com.zyx.crawlerdemo.makrocrawler.model.ProductModel;
import com.zyx.crawlerdemo.makrocrawler.parse.Parse;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

/**
 * @author Yaxi.Zhang
 * @since 2021/8/12 15:20
 * desc: WebCollector数据入库案例
 * 		采集的网站为: https://www.makro.co.za/electronics-computers/cellphones/c/BG
 */
public class MakroCrawler extends BreadthCrawler {
	public static List<ProductModel> listPro = new ArrayList<>();
	public static List<ParameterModel> listPar = new ArrayList<>();
	public MakroCrawler(String crawlPath) {
		super(crawlPath, true);
		String url = "https://www.makro.co.za/electronics-computers/cellphones/c/BG";
		CrawlDatum datum = new CrawlDatum(url)
				// 第一层
				.type("firstLayer");
		this.addSeed(datum);
	}

	@Override
	public void visit(Page page, CrawlDatums next) {
		// 第一层次的页面, 获取所有品牌的URL, 并以此为第二层页面的入口
		if (page.matchType("firstLayer")) {
			// 解析第一层页面
			Elements results = page.
					select("div[data-js-media=true]").select("a");
			for (Element ele: results) {
				String urlNext = "https://www.makro.co.za" + ele.attr("href");
				// 添加第二层次需要访问的URL
				next.addAndReturn(urlNext).type("SecondLayer");
			}
		}

		// 第二层页面, 获取每个品牌对应的产品基本信
		if (page.matchType("SecondLayer")) {
			// 解析第二层次页面,并添加第三层次的页面URL
			Parse.getProductData(page, listPro, next);
		}
		if (page.matchType("ThirdLayer")) {
			// 解析第三层次页面
			Parse.getParData(page, listPar);
		}
	}

	public static void main(String[] args) throws Exception {
		MakroCrawler crawler = new MakroCrawler("crawl_makro");
		// 设置断点爬取
		/*crawler.setResumable(true);*/
		// 执行间隔,这里robots有限制,需要遵循robots协议
		crawler.getConf().setExecuteInterval(1000);
		// 连接超时
		crawler.getConf().setConnectTimeout(10000);
		// 读取数据超时
		crawler.getConf().setReadTimeout(10000);
		// 访问的线程数目
		crawler.setThreads(70);
		// 执行的深度
		crawler.start(5);
		/*
			注意:如果数据量较大,可以在visit()方法中每一条数据执行一次操作,以保证线程安全
				如果在visit()方法中直接执行集合插入
				操作(List or Vector线程并不安全),然后清空会导致数据插入不全
				针对少量的数据,可以在这里执行一次插入操作
		 */
		MysqlControl.executeInsertPro(listPro);
		MysqlControl.executeInsertPar(listPar);
	}
}
